package com.sdkj.fixed.asset.gateway.core.filters;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.sdkj.fixed.asset.api.login.pojo.LoginRole;
import com.sdkj.fixed.asset.api.login.pojo.LoginUser;
import com.sdkj.fixed.asset.api.login.pojo.LoginUserBase;
import com.sdkj.fixed.asset.common.base.BaseResultVo;
import com.sdkj.fixed.asset.common.core.RoleType;
import com.sdkj.fixed.asset.gateway.consumer.LogConsumer;
import com.sdkj.fixed.asset.gateway.consumer.UsageConsumer;
import com.sdkj.fixed.asset.gateway.core.consts.GatewayConstants;
import com.sdkj.fixed.asset.gateway.core.exception.enums.GatewayExceptionEnum;
import com.sdkj.fixed.asset.gateway.core.jwt.JwtTokenUtil;
import com.sdkj.fixed.asset.gateway.core.jwt.RedisUtil;
import com.sdkj.fixed.asset.pojo.UUIdGenId;
import com.sdkj.fixed.asset.pojo.system.LogManagement;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 请求号过滤器(全局过滤器)
 */
public class RequestNoFilter implements GlobalFilter, Ordered {
    private final Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public int getOrder() {
        return GatewayConstants.REQUEST_NO_ORDER;
    }
    @Autowired
    private RedisUtil redis;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private LogConsumer logConsumer;
    @Autowired
    private UsageConsumer usageConsumer;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         log.info("==================================>进入网关服务.............");
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //请求token信息
        String token = request.getHeaders().getFirst("token");
        /**
         * 获取ip
         */
        HttpHeaders headers = request.getHeaders();
        String ip = headers.getFirst("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = headers.getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getAddress().getHostAddress();
        }
        //请求路径
        String path=request.getPath().toString();
        //记录日志
        LogManagement t_log=new LogManagement();
        t_log.setUrl(path);
        t_log.setIp(ip);
        t_log.setTime(DateUtil.now());

        t_log.setId(new UUIdGenId().genId( "","" ));
        //判断是否需要校验
        Boolean isValidate = true;
        String requestPath = request.getPath().toString();
        for (NoValidateRequest reqUrl : NoValidateRequest.values()) {
            if (reqUrl.getUrl().equals(requestPath)) {
                t_log.setContent(reqUrl.getMes());
                isValidate = false;
            }
        }
        if(!isValidate){
            try {
                t_log.setOrgId("NONE");
                t_log.setUserId("");

                logConsumer.insertLog( t_log );
            }catch (Exception e){
                log.error( "feign客户端调用记录日志服务失败：" ,e);
            }
            return chain.filter(exchange);
        }
        if(StringUtils.isBlank(token)){
            DataBuffer buffer=unFilter( new BaseResultVo( GatewayExceptionEnum.TOKEN_EMPTY.getCode(), GatewayExceptionEnum.TOKEN_EMPTY.getMessage()),response );
            return response.writeWith(Mono.just(buffer));
        }

        //校验token信息有效性
        Integer checkToken = jwtTokenUtil.checkToken(token);
        if(checkToken == 2) {
            DataBuffer buffer = unFilter(new BaseResultVo(GatewayExceptionEnum.TIMEOUT_TOKEN.getCode(), GatewayExceptionEnum.TIMEOUT_TOKEN.getMessage()), response);
            return response.writeWith(Mono.just(buffer));
        }else if(checkToken == 3){
            DataBuffer buffer=unFilter( new BaseResultVo(GatewayExceptionEnum.ERROR_TOKEN.getCode(),GatewayExceptionEnum.ERROR_TOKEN.getMessage()),response );
            return response.writeWith(Mono.just(buffer));
        }
        String tokenUserId = jwtTokenUtil.getUserIdFromToken(token);
        log.info("tokenUserId"+tokenUserId+"____________________________________________");
        String userId = tokenUserId.replace("PC_", "").replace("APP_", "");
        t_log.setCuser(userId);
        t_log.setEuser(userId);
        //是否过期
        if(redis.get(tokenUserId) ==null || (!isSysadmin(tokenUserId) &&!((LoginUser) redis.get(tokenUserId)).getToken().equals(token))){
            DataBuffer buffer=unFilter( new BaseResultVo(GatewayExceptionEnum.TIMEOUT_TOKEN.getCode(),GatewayExceptionEnum.TIMEOUT_TOKEN.getMessage()),response );
            return response.writeWith(Mono.just(buffer));
        }

        String companyId = "NONE";
        if(!isSysadmin(tokenUserId)){
            companyId = ((LoginUser) redis.get(tokenUserId)).getCompanys().get(0).getCompanyId();
        }
        if(!isHasCompany(tokenUserId,request)){
            log.info("校验公司id===========================================");
            DataBuffer buffer=unFilter( new BaseResultVo(GatewayExceptionEnum.ORGID_EMPTY.getCode(),GatewayExceptionEnum.ORGID_EMPTY.getMessage()),response );
           // new LogicException("请先创建公司");
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            return response.writeWith(Mono.just(buffer));
        }

        //判断公司使用时间已过期
        try{
            BaseResultVo vo  = usageConsumer.getDxpireDayByCompanyId(companyId);
            if(vo != null){
                Integer day = (Integer) vo.getData();
                if(day != null && day < 0 ){
                    DataBuffer buffer = unFilter(new BaseResultVo(GatewayExceptionEnum.EXPIRE_DAY.getCode(), GatewayExceptionEnum.EXPIRE_DAY.getMessage()), response);
                    return response.writeWith(Mono.just(buffer));
                }
            }
        } catch (Exception e){
            log.error( "feign客户端调用公司使用剩余时间服务失败：" ,e);
        }


        //判断当前登录用户角色
        if(isSysadmin(tokenUserId)){
            try {
                t_log.setOrgId(companyId);
                t_log.setUserId(userId);
                logConsumer.insertLog( t_log );
            }catch (Exception e){
                log.error( "feign客户端调用记录日志服务失败：" ,e);
            }
            return chain.filter(exchange);
        }

        if(!isSysadmin(tokenUserId)){
            Object orgInfo = redis.get("orgInfo");
            if(orgInfo!=null){
                String belongToCompanyId = ((LoginUser) redis.get(tokenUserId)).getBelongToCompanyId();
                Map<String,Integer> orgMap = (Map<String, Integer>) orgInfo;
                Integer orgStatus = orgMap.get(belongToCompanyId);

                if(orgStatus!=null && orgStatus==2){
                    DataBuffer buffer=unFilter( new BaseResultVo(GatewayExceptionEnum.ORG_STATUS.getCode(),GatewayExceptionEnum.ORG_STATUS.getMessage()),response );
                    t_log.setContent(GatewayExceptionEnum.ORG_STATUS.getMessage());
                    try {
                        t_log.setOrgId(companyId);
                        t_log.setUserId(userId);
                        logConsumer.insertLog( t_log );
                    }catch (Exception e){
                        log.error( "feign客户端调用记录日志服务失败：" ,e);
                    }
                    return response.writeWith(Mono.just(buffer));
                }
            }
            try {
                t_log.setOrgId(companyId);
                t_log.setUserId(userId);
                logConsumer.insertLog( t_log );
            }catch (Exception e){
                log.error( "feign客户端调用记录日志服务失败：" ,e);
            }
        }

        return chain.filter(exchange);
    }

    private DataBuffer unFilter(BaseResultVo result,ServerHttpResponse response){
        String resultString = JSON.toJSONString(result);
        byte[] bits = resultString.getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //指定编码，否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
        return buffer;
    }
    private boolean isSysadmin(String token){
        LoginUserBase loginUser = (LoginUserBase)redis.get(token);
        if(loginUser == null){
            return false;
        }
        List<String> levels = new ArrayList<>();
        for(LoginRole roles : loginUser.getLoginRoles()){
            if(!levels.contains(roles.getRoleLevel())){
                levels.add(roles.getRoleLevel());
            }
        }
        if(levels != null && levels.contains(RoleType.SYSADMIN.getRoleType())){
            return true;
        }
        return false;
    }
    private boolean isHasCompany(String token, ServerHttpRequest request){
        LoginUser loginUser = (LoginUser)redis.get(token);
        if(loginUser == null){
            return false;
        }
       if(loginUser.getCompanys().size() == 0){
           String requestPath = request.getPath().toString();
           log.info("请求地址：=================================="+requestPath);
           for (NoNeedCompany reqUrl : NoNeedCompany.values()) {
               if (requestPath.startsWith(reqUrl.getUrl())) {
                   log.info("不需要校验==================================");
                   return true;
               }
           }
           return false;
       }
       return true;
    }
}
